/**
 * Copyright 2011 Google Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.api.adwords.starterkit.utils;

import com.google.api.adwords.lib.AdWordsService;
import com.google.api.adwords.lib.AdWordsServiceLogger;
import com.google.api.adwords.lib.AdWordsUser;
import com.google.api.adwords.starterkit.settings.StarterKitSettings;
import com.google.api.adwords.v201101.cm.AdGroupAdServiceInterface;
import com.google.api.adwords.v201101.cm.AdGroupCriterionServiceInterface;
import com.google.api.adwords.v201101.cm.AdGroupServiceInterface;
import com.google.api.adwords.v201101.cm.AdParamServiceInterface;
import com.google.api.adwords.v201101.cm.BulkMutateJobServiceInterface;
import com.google.api.adwords.v201101.cm.CampaignCriterionServiceInterface;
import com.google.api.adwords.v201101.cm.CampaignServiceInterface;
import com.google.api.adwords.v201101.cm.CampaignTargetServiceInterface;
import com.google.api.adwords.v201101.cm.ReportDefinitionServiceInterface;

import org.apache.log4j.Logger;

import java.io.File;

import javax.xml.rpc.ServiceException;

/**
 * The class <code>ServiceUtils</code> is a simple service provider for all
 * AdWords API services.
 *
 * @author rodrigo.f.vale@gmail.com (Rodrigo Vale)
 */
public final class ServiceUtils {
  private AdWordsUser user;
  private static final Logger log = Logger.getLogger("StarterKit");

  /**
   * Creates a <code>ServiceUtils</code> instance for a given <code>StarterKit
   * </code> settings.
   *
   * @param settings <code>StarterKit</code>'s settings for the campaign
   */
  public ServiceUtils(final StarterKitSettings settings) {
    final String useragent =
        settings.getName() + " v" + StarterKitSettings.getVersion();

    AdWordsServiceLogger.log();
    

    try {
      String pathToLog4JFile = System.getProperty("log4j.configuration");
      if (pathToLog4JFile != null) {
        File log4JFile = new File(pathToLog4JFile);
        if (log4JFile.exists()) {
          AdWordsServiceLogger.loadLog4JConfiguration(
            log4JFile.getAbsolutePath());
        }
        else {
          log.warn("Log4J Configuration File Not found - Using the standard logf4 configuration");
        }
      }
    } catch (Exception e) {
        log.warn(e.getMessage() + " - Using the standard logf4 configuration");
    }

    if (settings.doesUseSandbox()) {
      user = new AdWordsUser(settings.getLogin(), settings.getPassword(),
          settings.getClientLogin(), useragent, settings.getDevToken(), true);
    } else {
      if (settings.getClientLogin().length() > 0) {
        user =
            new AdWordsUser(settings.getLogin(), settings.getPassword(),
                settings.getClientLogin(), useragent, settings.getDevToken());
      } else {
        user =
            new AdWordsUser(settings.getLogin(), settings.getPassword(),
                useragent, settings.getDevToken());
      }
    }
  }

  /**
   * Returns instance of this AdWords user.
   *
   * @return an instance of this AdWords user
   */
  public AdWordsUser getAdWordsUser() {
    return user;
  }

  /**
   * Returns a campaign service associated with this AdWords user.
   *
   * @return a campaign service
   * @throws ServiceException if the <code>CampaignInterface</code> stub could
   *         not be generated
   */
  public CampaignServiceInterface getCampaignService() {
    int tries = 0;
    CampaignServiceInterface campaignService = null;
    do {
      try {
        campaignService = (CampaignServiceInterface) user.getService(
            AdWordsService.V201101.CAMPAIGN_SERVICE);
        tries = 2;
      } catch (ServiceException e) {
        tries++;
        log.debug(e.getMessage());
        Utils.sleep(30000);
      }
    } while (tries < 2);
    return campaignService;
  }

  /**
   * Returns a campaign criterion service associated with this AdWords user.
   *
   * @return a campaign criterion service
   * @throws ServiceException if the <code>CampaignInterface</code> stub could
   *         not be generated
   */
  public CampaignCriterionServiceInterface getCampaignCriterionService()
      throws ServiceException {
    return (CampaignCriterionServiceInterface) user.getService(
        AdWordsService.V201101.CAMPAIGN_CRITERION_SERVICE);
  }

  /**
   * Returns an ad group service associated with this AdWords user.
   *
   * @return an ad group service
   * @throws ServiceException if the <code>AdGroupInterface</code> stub could
   *         not be generated
   */
  public AdGroupServiceInterface getAdGroupService() {
    int tries = 0;
    AdGroupServiceInterface service = null;
    do {
      try {
        service = (AdGroupServiceInterface) user.getService(
            AdWordsService.V201101.ADGROUP_SERVICE);
        tries = 2;
      } catch (ServiceException e) {
        tries++;
        log.debug(e.getMessage());
        Utils.sleep(30000);
      }
    } while (tries < 2);
    return service;
  }

  /**
   * Returns a criterion service associated with this AdWords user.
   *
   * @return a criterion service
   * @throws ServiceException if the <code>CriterionInterface</code> stub could
   *         not be generated
   */
  public AdGroupCriterionServiceInterface getAdGroupCriterionService() {
    int tries = 0;
    AdGroupCriterionServiceInterface service = null;
    do {
      try {
        service = (AdGroupCriterionServiceInterface) user.getService(
            AdWordsService.V201101.ADGROUP_CRITERION_SERVICE);
        tries = 2;
      } catch (ServiceException e) {
        tries++;
        log.debug(e.getMessage());
        Utils.sleep(30000);
      }
    } while (tries < 2);
    return service;
  }

  /**
   * Returns a report definition service associated with this AdWords user.
   *
   * @return a report service
   * @throws ServiceException if the <code>ReportInterface</code> stub could not
   *         be generated
   */
  public ReportDefinitionServiceInterface getReportService() {
    int tries = 0;
    ReportDefinitionServiceInterface service = null;
    do {
      try {
        service =
            user.getService(AdWordsService.V201101.REPORT_DEFINITION_SERVICE);
        tries = 2;
      } catch (ServiceException e) {
        tries++;
        log.debug(e.getMessage());
        log.debug("Will try again in 30s...");
        Utils.sleep(30000);
      }
    } while (tries < 2);
    return service;
  }

  public BulkMutateJobServiceInterface getBulkMutateJobService()
      throws ServiceException {
    return user.getService(AdWordsService.V201101.BULK_MUTATE_JOB_SERVICE);
  }

  /**
   * Returns an ad service associated with this AdWords user.
   *
   * @return an ad service
   * @throws ServiceException if the <code>AdInterface</code> stub could not be
   *         generated
   */
  public AdGroupAdServiceInterface getAdService() {
    int tries = 0;
    AdGroupAdServiceInterface service = null;
    do {
      try {
        service = (AdGroupAdServiceInterface) user.getService(
            AdWordsService.V201101.ADGROUP_AD_SERVICE);
        tries = 2;
      } catch (ServiceException e) {
        tries++;
        log.debug(e.getMessage());
        Utils.sleep(30000);
      }
    } while (tries < 2);
    return service;
  }

  /**
   * Returns a Campaign Target service associated with this AdWords user.
   *
   * @return an ad service
   * @throws ServiceException if the <code>AdInterface</code> stub could not be
   *         generated
   */
  public CampaignTargetServiceInterface getCampaignTargetService()
      throws ServiceException {
    return (CampaignTargetServiceInterface) user.getService(
        AdWordsService.V201101.CAMPAIGN_TARGET_SERVICE);
  }

  public AdParamServiceInterface getAdParamService() {
    int tries = 0;
    AdParamServiceInterface service = null;
    do {
      try {
        service = (AdParamServiceInterface) user.getService(
            AdWordsService.V201101.AD_PARAM_SERVICE);
        tries = 2;
      } catch (ServiceException e) {
        tries++;
        log.debug(e.getMessage());
        Utils.sleep(30000);
      }
    } while (tries < 2);
    return service;
  }
}
